
require "crc"

module(..., package.seeall)

local logtag = "szy206_sw"
local cid, uid = 3, 3 -- 默认用3通道
local ubuf, nbuf = {}, {} -- 串口和网络数据buffer
local dtu, udtu, udata = {}, {} -- 配置文件
local status,isLogin = 0,false
function setDtu(dtup, udtup, udatap)
    dtu, udtu, udata = dtup, udtup, udatap
    -- 如果设置是本协议
    if udtu and tonumber(udtu.ntype) == 3 then sys.taskInit(init) end
end
local function getDeviceId()
    -- 410405 04 0001 测试平顶山学院1#
    -- udtu.dsn = '410405040002' --测试
    if udtu and udtu.dsn and #udtu.dsn > 11 then
        deviceid = udtu.dsn:sub(1, 6) -- 省市代码3个字节BCD
        deviceid = deviceid .. string.format("%02X", tonumber(udtu.dsn:sub(-3))) -- 序列号9bit，不能超过255
        deviceid = deviceid .. udtu.dsn:sub(8, 9) -- 厂家（4bit）+设备类型（2bit） 00用水户，01地表水，10明渠，11排污口
        return deviceid
    end
end
local function getLogin(isHB)
    -- login  680868 B0 410405 01 40 02F0 FE 16
    --        680868 B0 410405 01 40 02F0 FE 16
    loginStr = "680868" -- 登录数据域长度8字节
    deviceid = getDeviceId()
    data = "B0" -- 控制码
    if (deviceid) then data = data .. deviceid .. (isHB and "02F2" or "02F0") end -- 02线路检测命令 F0登录，F2心跳，F1登出
    if (#data > 11) then loginStr = loginStr .. data .. string.format("%02X",crc.crc8(data:fromHex())) .. "16" end
    return loginStr
end
local function sendHB()
    sys.publish("NET_SENT_RDY_" .. (cid or 3), (getLogin(false)):fromHex()) -- 使用登陆代替心跳
    status = 2
end
local function login()
    sys.publish("NET_SENT_RDY_" .. (cid or 3), (getLogin(false)):fromHex()) 
    status = 0
end
function process(data, status)
    -- 68086830410405014002F09816 登陆成功
    if (status == 0 and (data:sub(10, 11)):toHex() == "02F0") then
        sys.publish("NET_SENT_RDY_1", "szy-206 LOGIN OK")
        isLogin = true
        update(false)
        -- 680868334104050140C0008216 上报成功
    elseif (status == 1 and (data:byte(10) == 0xC0) or data:byte(10) == 0xB0) then
        sys.publish("NET_SENT_RDY_1", "szy-206 UPDATA OK")
        usrdata.IS_UP_OK_3 = true
        lcd.USR_STATUS = ' UPOK3'
        if usrdata.IS_UP_OK_1 then sys.publish("RTU_POWER_OFF") end
    else
        if data:byte(10) == 0xB0 then -- 召测
            update(true)
        end
    end
end
function valToBCD(val) -- 1548870->7088540100
    temp = tonumber(val)
    if not temp then return "00000000" end
    temp = string.format("%08d",math.floor(temp)) --8个字符4个字节
    res = temp:sub(7,8)..temp:sub(5,6)..temp:sub(3,4)..temp:sub(1,2)
    return res
end
function update(isCall)
    -- 等待读取数据
    isOK, data = sys.waitUntil("USRDATA_UPDATE", 20 * 1000)
    if isOK then
        dd = data
    else
        dd = usrdata.getVal()
    end
    --local dd = {dt=1647500418,val={水位（m）,水温}}
    -- 流量、水量参考 01548870 吨
    -- 681A68 B3 4104050140 C0 0000000000 7088540100 00003000 47261517 3C 20 16
    --        CN            FN 顺时流量    累计流量   测控器状态 秒分时日 3C上报时间间隔 =60   
    -- LL=1A (26个字节)
    -- 水位 123456 mm
    -- 68LL68 B2          4104050140 C0       00563412       00003000  47261517   3C                     20  16
    -- 头LL头 控制码（水位）          AFN：自报 水位（毫米）小端 测控器状态 秒分时日   3C上报时间间隔=60分钟   校验 尾
    -- LL=14（20个字节）
    if not dd or not dd.val or not dd.val[1] then
        log.error(logtag,"没有获取到设备数据，放弃上传")
        return
    end      
    dataAcc = valToBCD(dd.val[1]*1000) -- 123456 mm
    devStatus = "00003000"
    tm = misc.getClock()
    dt = string.format("%02d%02d%02d%02d",tm.sec,tm.min, tm.hour, tm.day).."3C"
    crcData = "B2" .. getDeviceId() .. (isCall and "B0" or "C0") ..dataAcc .. devStatus..dt
    len = string.format("%02X",#crcData/2)
    crc = string.format("%02X",crc.crc8(crcData:fromHex()))
    dataHex = "68..len..68"..crcData..crc..16
    sys.publish("NET_SENT_RDY_" .. (cid or 3), dataHex:fromHex())
    log.warn(logtag,"socket send update:"..dataHex)
    status=1
end
function init()
    sys.subscribe("DTU_ALARM_ON", function() sys.taskInit(update,false) end)--在实时在线模式时触发
    cid = (cid or 3) -- 网络通道id，对应uartid
    while true do
        isLogin = false
        while not socket.isReady() or not create.getDatalink(cid) do
            log.warn(logtag, "等待net[" .. cid .. "] connect...")
            sys.wait(1000)
        end
        login()
        while create.getDatalink(cid) do
            -- 等待有网络下发数据，或者到指定的上报时间间隔
            result, id, data = sys.waitUntil("NET_RECV_WAIT_" .. cid, (tonumber(dtu.conf[cid][3]) or 180) * 1000)
            -- result, id, data = sys.waitUntil("NET_RECV_WAIT_" .. cid, 5 * 1000)
            -- 网络下发命令
            if result then
                if data then
                    log.warn(logtag, string.format("收到网络[%s]数据[status:%s]:%s", id, status, data:toHex()))
                    process(data, status)
                end
            else -- 超时(已到指定的时间间隔)
                log.warn(logtag, "发送心跳")
                sendHB()
            end
            if not isLogin then break end
        end
    end
end

